package com.zhaopin.qa.jmeter.plugins.jsonschemaassertion;

import java.io.File;
import java.io.IOException;
import java.io.Serializable;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.jmeter.assertions.Assertion;
import org.apache.jmeter.assertions.AssertionResult;
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jmeter.testelement.AbstractTestElement;
import org.apache.jorphan.logging.LoggingManager;
import org.apache.log.Logger;
import org.everit.json.schema.Schema;
import org.everit.json.schema.ValidationException;
import org.everit.json.schema.loader.SchemaLoader;
import org.everit.json.schema.loader.SchemaLoader.SchemaLoaderBuilder;
import org.everit.json.schema.loader.SpecificationVersion;
import org.json.JSONException;
import org.json.JSONObject;

public class JSONSchemaAssertion extends AbstractTestElement implements Serializable, Assertion {

	private static final long	serialVersionUID	= -6481241004026948992L;

	private static final Logger	log					= LoggingManager.getLoggerForClass();

	public static final String	SCHEMA_VERSION		= "json_schema_version";
	public static final String	SCHEMA_FILENAME_KEY	= "json_schema_assertion_filename";
	public static final String	SCHEMA_CONTENT_KEY	= "json_schema_assertion_schema";

	public JSONSchemaAssertion() {
		setProperty(SCHEMA_VERSION, SpecificationVersion.DRAFT_4.name());
	}

	public void setSchemaFileName(String jsonSchemaFileName) {
		setProperty(SCHEMA_FILENAME_KEY, jsonSchemaFileName);
	}

	public String getSchemaFileName() {
		return getPropertyAsString(SCHEMA_FILENAME_KEY);
	}

	public void setSchemaVersion(SpecificationVersion version) {
		setProperty(SCHEMA_VERSION, version.name());
	}

	public SpecificationVersion getSchemaVersion() {
		String name = getPropertyAsString(SCHEMA_VERSION);
		return SpecificationVersion.valueOf(name);
	}

	public void setSchemaContent(String text) {
		setProperty(SCHEMA_CONTENT_KEY, text);
	}

	public String getSchemaContent() {
		return getPropertyAsString(SCHEMA_CONTENT_KEY);
	}

	private Schema getSchema(JSONObject jsonSchema) {
		SchemaLoaderBuilder schemaJson = SchemaLoader.builder().schemaJson(jsonSchema);
		switch (getSchemaVersion()) {
			case DRAFT_7:
				schemaJson.draftV7Support();
				break;
			case DRAFT_6:
				schemaJson.draftV6Support();
				break;
			case DRAFT_4:
			default:
				break;
		}
		return schemaJson.build().load().build();
	}

	/**
	 * 断言jsonschema
	 */
	@Override
	public AssertionResult getResult(SampleResult response) {
		AssertionResult	result		 = new AssertionResult(getName());

		String			responseData = response.getResponseDataAsString();

		/**
		 * 1.判断响应是否为空</br>
		 * 2.判断响应是否是json</br>
		 * 3.获取json模板</br>
		 * 3.1 判断是否有文件模板</br>
		 * 3.1.*文件模板相关操作</br>
		 * 3.2 判断是否有文本模板</br>
		 * 4.检查模板是否json JsonLoader.fromString(schema);</br>
		 * 5.套用模板 进行验证</br>
		 * 6.分析验证结果</br>
		 */

		// 1.判断响应是否为空</br>
		if (responseData.length() == 0) { return result.setResultForNull(); }

		// 2.判断响应是否是json</br>
		JSONObject responseJson;
		try {
			responseJson = new JSONObject(responseData);
		} catch (JSONException e) {
			log.warn(getName() + "断言时报错：" + e.getMessage());
			return result.setResultForFailure("响应结果不是json格式！");
		}

		// 3.获取json模板</br>
		// 3.1 判断是否有文件模板</br>
		// 3.1.*文件模板相关操作</br>
		String schemaFileName = getSchemaFileName();
		String schemaContent  = getSchemaContent();

		// 检查schema是否有效
		Schema schema;
		try {
			// 获取schema
			if (StringUtils.isNotBlank(schemaFileName)) {
				String schemaFromFile = FileUtils.readFileToString(new File(schemaFileName));
				schema = getSchema(new JSONObject(schemaFromFile));
			} else
				if (StringUtils.isNotBlank(schemaContent)) {
					schema = getSchema(new JSONObject(schemaContent));
				} else {
					return result.setResultForFailure("未设置json schema！");
				}
		} catch (IOException e) {
			log.warn(getName() + "断言时报错：", e);
			return result.setResultForFailure("json schema格式有误！" + e.getMessage());
		}

		// 验证
		try {
			schema.validate(responseJson);
		} catch (ValidationException e) {
			final StringBuffer sv = new StringBuffer();
			e.getAllMessages().forEach(err -> sv.append(err).append("\n"));
			log.warn(getName() + "断言时报错：" + e.getAllMessages());
			return result.setResultForFailure(sv.toString());
		} catch (Exception e) {
			log.warn(getName() + "断言时报错：" + e.getMessage());
			result.setError(true);
			result.setFailureMessage(e.getMessage());
			return result;
		}
		return result;
	}
}
